package grammar.parser;

import execution.Executable;
import exp.parser.ExpParser;
import word.parser.WordElement;

import java.util.ArrayList;
import java.util.List;

public class CompUnit extends GrammarParser implements Executable {
    private final List<Decl> decls;
    private final List<FuncDef> funcDefs;
    private final MainFuncDef mainFunc;

    private CompUnit(List<Decl> decls, List<FuncDef> funcDefs, MainFuncDef mainFunc) {
        this.decls = decls;
        this.funcDefs = funcDefs;
        this.mainFunc = mainFunc;
    }


    public static CompUnit buildCompUnit() {
        List<Decl> decls = new ArrayList<>();
        List<FuncDef> funcDefs = new ArrayList<>();
        MainFuncDef mainFuncDef = null;
        while (getAnalyzingWord() != null) {
            if (getAnalyzingWord().getType() == WordElement.WordType.CONSTTK) {
                decls.addAll(Decl.buildDecl());
            } else if (getAnalyzingWord().getType() == WordElement.WordType.INTTK) {
                if (getAnalyzingWord(1).getType() == WordElement.WordType.IDENFR) {
                    if (getAnalyzingWord(2).getType() == WordElement.WordType.LPARENT) {
                        funcDefs.add(FuncDef.buildFuncDef());
                    } else {
                        decls.addAll(Decl.buildDecl());
                    }
                } else if (getAnalyzingWord(1).getType() == WordElement.WordType.MAINTK) {
                    mainFuncDef = MainFuncDef.buildMainFunc();
                    break;
                } else {
                    throw new RuntimeException("Unknown Exception");
                }
            } else if (getAnalyzingWord().getType() == WordElement.WordType.VOIDTK) {
                funcDefs.add(FuncDef.buildFuncDef());
            }
        }
        assert mainFuncDef != null;
        return new CompUnit(decls, funcDefs, mainFuncDef);
    }

    @Override
    public void execute() {
        getSemanticParser().reset();
        ExpParser.initBeforeExecute();
        for (Decl decl : decls) {
            decl.execute();
        }
        for (FuncDef funcDef : funcDefs) {
            getSemanticParser().declFunc(funcDef, 0);
        }
        mainFunc.execute();
    }
}

